using System.Text;
using NFreeMarker.Template;

namespace NFreeMarker.Core
{
    /**
     * A reference to a built-in identifier, such as .root
     */
    public sealed class BuiltinVariable : Expression // NOTE: Was internal
    {
        private const string TemplateName = "template_name";
        private const string Namespace = "namespace";
        private const string Main = "main";
        private const string Globals = "globals";
        private const string Locals = "locals";
        private const string DataModel = "data_model";
        private const string Lang = "lang";
        private const string Locale = "locale";
        private const string CurrentNode = "current_node";
        private const string Node = "node";
        private const string Pass = "pass";
        private const string Vars = "vars";
        private const string Version = "version";
        private const string Error = "error";
        private const string OutputEncoding = "output_encoding";
        private const string UrlEscapingCharset = "url_escaping_charset";

        private readonly string _name;

        internal BuiltinVariable(string name)
        {
            // TODO name = name.intern();
            _name = name;
            if (name != TemplateName &&
                name != Namespace &&
                name != Main &&
                name != Globals &&
                name != Locals &&
                name != Lang &&
                name != Locale &&
                name != DataModel &&
                name != CurrentNode &&
                name != Node &&
                name != Pass &&
                name != Vars &&
                name != Version &&
                name != OutputEncoding &&
                name != UrlEscapingCharset &&
                name != Error)
            {
                throw new ParseException("Unknown built-in variable: " + name, this);
            }
        }

        protected override ITemplateModel _getAsTemplateModel(Environment env)
        {
            switch (_name)
            {
                case Namespace:
                    return env.GetCurrentNamespace();
                case Main:
                    return env.GetMainNamespace();
                case Globals:
                    return env.GetGlobalVariables();
                case Locals:
                    return env.GetCurrentMacroContext().GetLocals();
                case DataModel:
                    return env.GetDataModel();
                case Vars:
                    return new VarsHash(env);
                case Locale:
                    return new SimpleScalar(env.GetLocale().ToString());
                case Lang:
                    return new SimpleScalar(env.GetLocale().TwoLetterISOLanguageName);
                case Node:
                case CurrentNode:
                    return env.GetCurrentVisitorNode();
                case TemplateName:
                    return new SimpleScalar(env.GetTemplate().GetName());
                case Pass:
                    return Macro.DoNothingMacro;
                case Version:
                    return new SimpleScalar(Configuration.GetVersionNumber());
                case OutputEncoding:
                    {
                        Encoding s = env.GetOutputEncoding();
                        return s != null ? new SimpleScalar(s.WebName) : null;
                    }
                case UrlEscapingCharset:
                    {
                        Encoding s = env.GetUrlEscapingCharset();
                        return s != null ? new SimpleScalar(s.WebName) : null;
                    }
                case Error:
                    return new SimpleScalar(env.GetCurrentRecoveredErrorMesssage());
            }
            throw new TemplateException("Invalid built-in variable: " + this, env);
        }

        public override string ToString()
        {
            return "." + _name;
        }

        public override string GetCanonicalForm()
        {
            return "." + _name;
        }

        internal override bool IsLiteral()
        {
            return false;
        }

        protected override Expression DeepCloneImpl(string name, Expression subst)
        {
            return this;
        }

        private class VarsHash : ITemplateHashModel
        {
            private readonly Environment _env;

            public VarsHash(Environment env)
            {
                _env = env;
            }

            public ITemplateModel Get(string key)
            {
                return _env.GetVariable(key);
            }

            public bool IsEmpty()
            {
                return false;
            }
        }
    }
}